<?php
Namespace Cyfy\Modules\Modules;
use \Cyfy\Message as Message;

/**
 * Class handling module administration.
 *  
 * @author Dandelion
 * @version 0.1
 */
class Module extends \Cyfy\Module
{
    /**
     * All modules, which are in the /modules folder. Doesn't have to be uninstalled.
     * @var array
     */
    static public $allModules = array();
    
    
    /**
     * Administration UI
     * @param string name
     * @return mixed
     */
	static function administration($name = '')
	{
        switch($name)
        {
            case "modules":
                return self :: main();
            default:
                return array(
                    "modules" => array("name" => self :: t(10), "description" => self :: t(20), "permission" => "administration"),
                );
		}	
	}
	
    /**
     * AJAX callback.
     * @param string
     * @return mixed
     */
	static function ajax($name)
	{
		switch($name)
		{
			case "changeState":
				return self :: changeState($_POST);
		}
	}
    
    /**
     * Calls
     * @param string
     */
    static function call($name)
    {
        switch($name){
            case "createTables":
                self :: callCreateTables();
                break;
            case "createFilesystem":
                self :: callCreateFilesystem();
                break;
        }
    }

    /**
     * Loads modules from directory and inserts them into array.
     */
    static public function loadModules()
    {
        // get folders from directory
		$directory = scandir(\Cyfy\Cyfy ::  $modulesDir);
        array_shift($directory); // removes .
		array_shift($directory); // removes ..
        self :: $allModules = array();
        foreach($directory as $classname)
        {
			if(file_exists(\Cyfy\Cyfy ::  $modulesDir . $classname . "/info.xml"))
            {
				self :: $allModules[] = $classname;
            }
		}
        return self :: $allModules;
    }
    
    /**
     * Loads modules and creates filesystem for all modules
     */
    static private function callCreateFilesystem()
    {
        self :: loadModules();
        
        foreach(self :: $allModules as $module)
        {
            self :: createFilesystemFromXML($module);
        }
    }
    
    /**
     * Create filesystem for module.
     * Check log file for output.
     *
     * @param string module name
     * @return bool
     */
    static public function createFilesystemFromXML($module)
    {
        $xmlFile = \Cyfy\Cyfy ::  $modulesDir . $module . "/filesystem.xml";
        if(!file_exists($xmlFile))
        {   
            return true;
        }
        
        $xml = simplexml_load_file($xmlFile);
        if(!$xml)
        {
            \Cyfy\Log :: writeError("An error occured when parsing $xmlFile.");
            return false;
        }

        // checks paths
   		foreach($xml -> entry as $entry)
        {
            if(!\Cyfy\Cyfy ::  tryPath((string) $entry -> path, true))
            {
                \Cyfy\Message::set(self :: t(202, array($module, (string) $entry -> path)), \Cyfy\Message::ERROR);
                return false;
            }
        }
        
        // inserts paths
		foreach($xml -> entry as $entry)
        {
            if(\Cyfy\Cyfy ::  registerPath((string) $entry -> path, $module, (string) $entry -> id, (string) $entry -> name, (string) $entry -> permission, true))
            {
                \Cyfy\Log :: write("Path " . (string) $entry -> path . " for $module has been registered.");
            }
        }
        return true;
    }
    
    /**
     * Creates tables for all modules in the folder.
     */
    static public function callCreateTables()
    {
        self :: loadModules();
        
        foreach(self :: $allModules as $module)
        {
            if(self :: createTablesFromXML($module))
            {
                \Cyfy\Log :: Write("Tables for $module created.");
            }
        }
    }
    
    /**
     * Creates tables for a module
     *
     * @param string Module name
     * @return bool
     */
    static public function createTablesFromXML($module)
    {
        $xmlFile = \Cyfy\Cyfy ::  $modulesDir . $module . "/tables.xml";
        if(!file_exists($xmlFile))
        {   
            return true;
        }
        
        $xml = simplexml_load_file($xmlFile);
        
        if(!$xml)
        {
            \Cyfy\Log :: WriteError("An error occured when parsing $xmlFile.");
            return false;
        }
        $i = 0;
        foreach($xml -> table_structure as $fields)
        {
            $primaryKeys = array();
            $sql = "CREATE TABLE IF NOT EXISTS [:cyfy:" . $xml -> table_structure[$i]["name"] ."] (\n";
            foreach($fields as $field)
            {
                $default = ($field["Default"]) ? " default '{$field["Default"]}'" : "";
                $null = ($field["Null"] == "NO") ? "NOT NULL" : "NULL";
                $sql .= "[{$field["Field"]}] {$field["Type"]} {$null} {$field["Extra"]}{$default},\n";
                if($field["Key"] == "PRI")
                {
                    $primaryKeys[] = "[{$field["Field"]}]";
                }
            }
            $sql .= " PRIMARY KEY (" . implode(", ", $primaryKeys) . ")\n";
            $sql .= ") DEFAULT CHARSET=utf8;";
            \dibi::query($sql);
            $i++;
        }
        return true;
    }
    
    /**
     * Deletes table for a module
     * @param string Module name
     */
    static public function dropTablesFromXML($module)
    {
        $xmlFile = \Cyfy\Cyfy ::  $modulesDir . $module . "/tables.xml";
        if(!file_exists($xmlFile))
        {   
            return false;
        }
        
        $xml = simplexml_load_file($xmlFile);
        
        if(!$xml)
        {
            \Cyfy\Log :: writeError("An error occured when parsing $xmlFile.");
            return false;
        }
        $i = 0;
        foreach($xml -> table_structure as $fields)
        {
            $primaryKeys = array();
            $name = (string) $xml -> table_structure[$i]["name"];
            \dibi :: query("DROP TABLE [:cyfy:$name]");
            $i++;
        }
        return true;
    }
  
  
	static function main()
	{
		\Cyfy\Cyfy ::  CSS(\Cyfy\Cyfy ::  getSourcePath("Cyfy/Modules/Modules/modules-admin.css"));
        self :: loadModules();
        
    	
		// get currently installed modules
		$result = \dibi :: query("SELECT [name],[state] FROM [:cyfy:Modules]");
        $installed = $result -> fetchPairs('name', 'state');
		
        // this finds xmls and sends it to parse
		foreach(self :: $allModules as $classname)
        {
			$module = \Cyfy\Modules :: getInfo($classname);
            $modules[$module["project"]][] = $module;        
		}
   

		// going through the array of modules
		foreach($modules as $project => $modulesInProject)
		{
			$data = "";
			
			$table = new \Cyfy\Modules\Objects\Table("modulesTable");
			$table -> header(array("mname" => self :: t(30), "mversion" => self :: t(40), "mstatus" => self :: t(50)));
			
			foreach($modulesInProject as $module)
			{
				$table -> row(array($module["name"], $module["version"], "<div class=\"module-state-wrapper\" id=\"module-{$module["classname"]}\">" . self :: stateButtons($module["classname"], $installed[$module["classname"]]) . "</div>" ));
			}
			$output .= "<h2>" . $project . "</h2>\n" . $table -> show();
		}
		return "<p>" . self :: t(60) . "</p><div id=\"listOfModules\">\n" . $output . "\n</div>";
	}
 
    /**
     * Returns buttons for a module
     *
     * @param string Path, where module is installed.
     * @param string State
     */
	static function stateButtons($classname, $installed = "0")
	{
		if(!$installed){
			// search for modules in the DB
			$installed = \dibi :: query("SELECT [state] FROM [:cyfy:Modules] WHERE [name] = %s LIMIT 1", $classname) -> fetchSingle();
		}
		if(!$installed) $installed = "0";
		switch($installed){
			case "0":
				$installedName = self :: t(100);
				$installedClass = "stateNotInstalled";
				break;
			case "1":
				$installedName = self :: t(110);
				$installedClass = "stateDisabled";
				break;
			case "2":
				$installedName = self :: t(120);
				$installedClass = "stateRunning";
				break;
			default:
				$installedName = "";
				$installedClass = "";
				break;
		}
        
			
		$output .= "    <span class=\"state $installedClass\">$installedName</span><span class=\"moduleButtons\">\n";
        
        if($classname == 'Cyfy') return $output;
        
		if($installed == "0"){
			$output .= "         <span title=\"". self :: t(130)."\"><input class=\"button-ok\" type=\"submit\" name=\"\" onclick=\"Cyfy.ajax('Modules', 'changeState', '#module-$classname', 'module-classname=$classname&module-do=install-run');\" value=\"I&R\" /></span>\n";
			$output .= "         <span title=\"". self :: t(140)."\" ><input class=\"button-ok\" type=\"submit\" name=\"\" onclick=\"Cyfy.ajax('Modules', 'changeState', '#module-$classname', 'module-classname=$classname&module-do=install');\" value=\"I\" /></span>\n";
		}
		if($installed == "1"){
			$output .= "         <span title=\"". self :: t(150)."\"><input class=\"button-ok\" type=\"submit\" name=\"\" onclick=\"Cyfy.ajax('Modules', 'changeState', '#module-$classname', 'module-classname=$classname&module-do=enable');\" value=\"E\" /></span>\n";
		}
		if($installed == "2"){
			$output .= "         <span title=\"". self :: t(160)."\"><input class=\"button-neutral\" type=\"submit\" name=\"\" onclick=\"Cyfy.ajax('Modules', 'changeState', '#module-$classname', 'module-classname=$classname&module-do=disable');\" value=\"D\" /></span>\n";
		}
		if($installed == "2" || $installed == "1"){
			$output .= "         <span title=\"". self :: t(170)."\"><input class=\"button-warning\" type=\"submit\" name=\"\" onclick=\"if(confirm('".self::t(171, array($classname))."')){ Cyfy.ajax('Modules', 'changeState',  '#module-$classname', 'module-classname=$classname&module-do=uninstall'); }\"  value=\"U\"  /></span>\n";
		}
		$output .= "</span>";
				
		return $output;
	}
	
    /**
     * Changes state of a module.
     * @param array Associative information about module. Keys are: 'module-classname', 'module-classname', 'module-do'
     * @return mixed
     */	
	static public function changeState($array)
	{
		$classname = $array["module-classname"];
		
        $class = "\Cyfy\Modules\\" . $classname . "\Setup";
		
        $setupFile = classToPath($class) . '.php';
        // try to load own setupclass
		if(file_exists($setupFile)){	
			include_once($setupFile);
		}
        else
        {
			$class = "\Cyfy\ModuleSetup";
		}
        
        $info = \Cyfy\Modules :: getInfo($classname);
		if($info)
        {
            $class :: $info = $info;
            $class :: changeState($array["module-do"]);
            return self :: stateButtons($classname);
        }
        \Cyfy\Message :: set(self :: t(180), \Cyfy\Message :: ERROR);
        return false;
	}
    
    /**
     * Checks dependecies, when disabling/uninstalling a module.
     */
    static public function checkDependenciesWhenDisabling($classname)
    {
        
        // modules, which depends on it
        $modules = array();

        // listing active modules
        foreach(\Cyfy\Modules :: getEnabled() as $c)
        {
            $module = \Cyfy\Modules :: getInfo($c);
            if(in_array($classname, $module['dependencies']))
            {
                $modules[] = $module['name'];
            }
        }
    
        // if some modules
        if(count($modules))
        {
            \Cyfy\Message :: set(self :: t(201, array(implode(', ', $modules))), \Cyfy\Message::ERROR);
            return false;
        }
        
        return true;
    }
    
    /**
     * Checks dependecies, when installing a module.
     */
    static public function checkDependenciesWhenInstalling($moduleToInstallInfo)
    {
        if(!is_array($moduleToInstallInfo))
        {
            return false;
        }
        
        // if no dependecies - true
        if(!count($moduleToInstallInfo['dependencies']))
        {
            return true;
        }

        // get enabled from DB
        $enabled = array();
        $result = \dibi :: query('SELECT [name] FROM [:cyfy:Modules] WHERE [state] = 2');
        foreach($result as $m){
            $enabled[] = $m['name'];
        }
        
        // listing active modules
        foreach($moduleToInstallInfo['dependencies'] as $uniq)
        {
            if(!in_array($uniq, $enabled))
            {
                $modules[] = $uniq;
            }
        }
    
        // if some modules
        if(count($modules))
        {
            \Cyfy\Message :: set(self :: t(211, array(implode(', ', $modules))), \Cyfy\Message::ERROR);
            return false;
        }
        
        return true;
    }
}




